package me.baicai.weixin.provider.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.qiniu.util.Auth;
import com.qiniu.util.StringMap;
import lombok.extern.slf4j.Slf4j;
import me.baicai.weixin.application.BasicService;
import me.baicai.weixin.application.Result;
import me.baicai.weixin.conf.OrderKey;
import me.baicai.weixin.conf.WeiXinKey;
import me.baicai.weixin.entity.config.ShopMenu;
import me.baicai.weixin.entity.gcb.Device;
import me.baicai.weixin.entity.identity.Shop;
import me.baicai.weixin.entity.order.Account;
import me.baicai.weixin.entity.order.FaultRecord;
import me.baicai.weixin.entity.order.MoneyLog;
import me.baicai.weixin.entity.order.Order;
import me.baicai.weixin.identity.repository.*;
import me.baicai.weixin.identity.service.AdverTisingService;
import me.baicai.weixin.provider.repository.FaultRecordRepository;
import me.baicai.weixin.provider.repository.ProductRepository;
import me.baicai.weixin.provider.service.OrderService;
import me.baicai.weixin.provider.utils.MD5Algorithm;
import me.baicai.weixin.provider.utils.OrderGenerator;
import me.baicai.weixin.utils.DateRange;
import me.baicai.weixin.utils.HttpClient;
import me.baicai.weixin.utils.WeiXinUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;


@Slf4j
@Service
public class OrderServiceImpl extends BasicService implements OrderService
{

    @Autowired
    private ProductRepository productRepository;

    @Autowired
    private DeviceRepository deviceRepository;

    @Autowired
    private MD5Algorithm md5Algorithm;

    @Autowired
    private FaultRecordRepository faultRecordRepository;

    @Autowired
    private MoneyLogRepository moneyLogRepository;

    @Autowired
    private OrderRepository orderRepository;

    @Autowired
    private AccountRepository accountRepository;

    @Autowired
    private ShopMenuRepository shopMenuRepository;

    @Autowired
    private ShopRepository shopRepository;

    @Autowired
    private AdverTisingService adverTisingService;

    @Value(value = "${qiniu.accessKey}")
    private String accessKey;

    @Value(value = "${qiniu.secretKey}")
    private String secretKey;

    @Value(value = "${qiniu.region}")
    private String region;

    @Value(value = "${qiniu.domain}")
    private String domain;

    @Value(value = "${qiniu.bucket}")
    private String bucket;

    @Value(value = "${qiniu.expireSeconds}")
    private long expireSeconds;   //过期时间

    @Override
    public Result orderMenu(String openid, String sn, String city, String region)
    {

        // 先判断是否存在
        Device device = deviceRepository.findBySn(sn);

        if (null == device)
            return this.error(404, "未激活的设备");

        // 先判断这个设备下面是否有订单进行中
        /*if (orderRepository.existsByDevicesnAndOrderstatus(sn, OrderKey.进行中))
        {
            return this.error(409, "该设备正在使用中");
        }*/

        // 先判断这个用户下面是否有订单进行中
        if (orderRepository.existsByCustomeridAndOrderstatus(openid, OrderKey.进行中))
        {
            return this.error(500,
                orderRepository.findOrderByCustomeridAndOrderstatus(openid, OrderKey.进行中));
        }

        Map map = new HashMap();
        map.put("product", productRepository.findAllByShopIdAndIsuse(device.getShopid(), 1));
        map.put("advertising",
            adverTisingService.shopAdvertising(device.getShopid(), city, region));
        map.put("shop", shopRepository.getById(device.getShopid()));
        return this.success(map);
    }

    @Override
    public Result getToken()
    {
        Map qiNiu = new HashMap();
        StringMap putPolicy = new StringMap();
        Auth auth = Auth.create(accessKey, secretKey);
        String upToken = auth.uploadToken(bucket, null, expireSeconds, putPolicy);
        qiNiu.put("key", UUID.randomUUID().toString().replaceAll("\\-", "") + ".jpg");
        qiNiu.put("token", upToken);
        qiNiu.put("region", this.region);
        qiNiu.put("domain", this.domain);
        return this.success(qiNiu);
    }

    public Result passwd(Order order, int key)
    {

        if (order.getOrderscore() > 5)
            return this.error("只有五次重置密码和激活设备的机会!");
        // 先获取当前设备的密码下标
        Device device = deviceRepository.findBySn(order.getDevicesn());
       /*switch (key)
        {
            case 1:
                order.setTime(1 * 60 * 60);
                break;
            case 2:
                order.setTime(2 * 60 * 60);
                break;
            case 3:
                order.setTime(12 * 60 * 60);
                break;
            case 4:
                order.setTime(24 * 60 * 60);
                break;
        }*/
        if (device.getVersion() < 3)
        {
            order.setPasswd(md5Algorithm.passwordCalculation(order.getDevicesn(), device, key));
        }
        else if (device.getVersion() == 3)
        {
            order.setPasswd(
                md5Algorithm.bluetoothPasswd(order.getDevicesn(), order.getTime() / 60));
        }
        order.setOrderscore(order.getOrderscore() + 1);
        deviceRepository.saveAndFlush(device);
        orderRepository.save(order);
        order.setShop(shopRepository.getById(order.getShopid()));
        return this.success(order);
    }

    @Override
    public Result fault(String openid, String sn, String tel, String message, String images,
                        String info)
    {

        // 查询这个设备的订单-同时只会存在一个订单
        Order order = orderRepository.findOrderByDevicesnAndOrderstatus(sn, OrderKey.进行中);
        if (null == order)
            return this.error(404, "未查询到相关订单");


        if (null != message && !"".equalsIgnoreCase(message) && message.contains("["))
        {
            message = message.substring(1, message.length() - 2);
        }

        // 保存故障记录
        FaultRecord faultRecord = new FaultRecord(sn, tel, message, images, new Date(),
            order.getId(), order.getShopid());
        faultRecord.setInfo(info);
        faultRecordRepository.save(faultRecord);

        if (order.getPaytype().equalsIgnoreCase(OrderKey.PAY_余额))
        {
            Account account = accountRepository.findAccountByOpenid(openid);
            account.setBalance(order.getAmount() + account.getBalance());
            accountRepository.saveAndFlush(account);
            // 修改状态为取消
            order.setOrderstatus(OrderKey.取消并且退款);
            order.setEnd(new Date());
            orderRepository.save(order);
            return success();
        }

        // 退款事宜
        Shop shop = shopRepository.getById(order.getShopid());
        if (new Date().getTime() - order.getCreated().getTime() > shop.getRefund() * 60 * 1000)
        {
            // 修改状态为取消
            order.setOrderstatus(OrderKey.取消未退款);
            order.setEnd(new Date());
            orderRepository.save(order);
            return this.success("故障已经上报,但是超过了自动退款时间,工作人员将手动退款!");
        }

        SortedMap<String, String> signParams = new TreeMap<String, String>();
        signParams.put("appid", WeiXinKey.appid);//app_id
        signParams.put("mch_id", WeiXinKey.mchid);//微信商户账号
        signParams.put("nonce_str",
            UUID.randomUUID().toString().replaceAll("-", ""));//32位不重复的编号
        signParams.put("out_refund_no", order.getId());//回调页面
        signParams.put("out_trade_no", order.getId());//订单编号
        signParams.put("refund_fee", ((int)(order.getAmount() * 100)) + "");//订单编号
        signParams.put("total_fee", ((int)(order.getAmount() * 100)) + "");//支付金额 单位为分
        signParams.put("sign", WeiXinUtils.MD5(signParams));
        String request = WeiXinUtils.MapToXml(signParams);
        JSONObject jsonObject = null;
        try
        {
            jsonObject = WeiXinUtils.convertXmlIntoJSONObject(
                WeiXinUtils.callWeiXin(request, WeiXinKey.refund));
            log.info(new Date() + " 微信退款记录 : " + jsonObject);
        }
        catch (Exception e)
        {
            e.printStackTrace();
        }
        order.setCallback(jsonObject.toJSONString());
        // 修改状态为取消
        order.setOrderstatus(OrderKey.取消并且退款);
        order.setEnd(new Date());
        orderRepository.save(order);
        return this.success("提交成功,即将退还支付金额,请关注微信支付消息");
    }

    @Override
    public Result resetPasswd(String id, String sn)
    {
        Order order = orderRepository.getOrderById(id);
        if (null == order)
            return this.error("订单不存在，或者已经结束");
        if (order.getOrderstatus().equals(OrderKey.待支付) ||
            order.getOrderstatus().equals(OrderKey.进行中))
        {
            order.setOrderstatus(OrderKey.进行中);
        }
        else
        {
            return this.error("订单不存在，或者已经结束");
        }
        return this.success(this.passwd(order, order.getGkey()));
    }

    @Override
    public Result withdrawalsRecord(String openid, String beginDate, String endDate)
    {
        List data = new ArrayList();
        SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd");
        SimpleDateFormat da = new SimpleDateFormat("yyyy 年 MM 月");
        DateRange d = null;
        try
        {
            d = new DateRange(df.parse(beginDate), df.parse(endDate));
        }
        catch (ParseException e)
        {
            e.printStackTrace();
        }
        List<DateRange> list = d.splitByMonth();
        list.forEach(x -> {

                Float f = moneyLogRepository.getAmountTotal(openid, OrderKey.SEC_提现,
                    df.format(x.getStart()).toString(), df.format(x.getEnd()).toString());

                Map map = new HashMap<>();
                map.put("month", da.format(x.getStart()));
                map.put("amount", f);
                if (0 != f)
                {
                    map.put("data",
                        moneyLogRepository.getAllByTargetidAndOrdersrc(openid, OrderKey.SEC_提现,
                            df.format(x.getStart()).toString(), df.format(x.getEnd()).toString()));
                }

                data.add(map);
            }
        );

        return this.success(data);
    }

    @Override
    public Result balance(String openid)
    {
        return this.success(accountRepository.findAccountByOpenid(openid));
    }

    @Override
    public Result createOrder(String openid, String sn, Integer key)
    {

        // 先判断这个设备下面是否有订单进行中
        if (orderRepository.existsByCustomeridAndOrderstatus(openid, OrderKey.进行中))
        {
            return this.error(500,
                orderRepository.findOrderByCustomeridAndOrderstatus(openid, OrderKey.进行中));
        }

        // 先判断这个设备下面是否有订单进行中
        /*if (orderRepository.existsByDevicesnAndOrderstatus(sn, OrderKey.进行中))
        {
            return this.error(409, "该设备正在使用中");
        }*/

        ShopMenu shopMenu = shopMenuRepository.getById(key);
        // 处理余额
        Account account = accountRepository.findAccountByOpenid(openid);
        account.setBalance(account.getBalance() - shopMenu.getPrice());
        Device device = deviceRepository.findBySn(sn);
        long currentTime = System.currentTimeMillis();

        // 创建订单
        Order order = new Order();
        order.setId(device.getModel() + OrderGenerator.OrderId());
        order.setCustomerid(openid);
        order.setShopid(device.getShopid());
        order.setDevicesn(sn);
        order.setOrderstatus(OrderKey.进行中);
        order.setCreated(new Date(currentTime));
        order.setPaytype(OrderKey.PAY_余额);
        order.setAmount(shopMenu.getPrice());
        order.setTime(shopMenu.getTime() * 60 * 60);
        order.setGkey(shopMenu.getGkey());
        order.setOrderscore(0); // 代表第一次
        order.setEnd(new Date(currentTime + shopMenu.getTime() * 60 * 60 * 1000));
        orderRepository.saveAndFlush(order);
        accountRepository.saveAndFlush(account);
        return this.passwd(order, order.getGkey());
    }

    @Override
    public Result closeOrder(String openid, String id)
    {
        Order order = orderRepository.findOrderByIdAndOrderstatus(id, OrderKey.进行中);
        if (null == order)
            return this.error(404, "不存在的订单");
        if (!order.getOrderstatus().equals(OrderKey.进行中))
            return this.error("订单状态异常");
        order.setOrderstatus(OrderKey.提前结束);
        order.setEnd(new Date());
        orderRepository.save(order);
        return this.success();
    }

    @Override
    public Result weixinPay(String openid, String sn, Integer id)
    {
        // 先判断这个用户下面是否有订单进行中
        if (orderRepository.existsByCustomeridAndOrderstatus(openid, OrderKey.进行中))
        {
            return this.error(500,
                orderRepository.findOrderByCustomeridAndOrderstatus(openid, OrderKey.进行中));
        }

        // 先判断这个设备下面是否有订单进行中
        /*if (orderRepository.existsByDevicesnAndOrderstatus(sn, OrderKey.进行中))
        {
            return this.error(409, "该设备正在使用中");
        }*/

        Device device = deviceRepository.findBySn(sn);
        ShopMenu shopMenu = shopMenuRepository.getById(id);
        // 创建订单
        long currentTime = System.currentTimeMillis();
        Order order = new Order();
        order.setId(device.getModel() + OrderGenerator.OrderId());
        order.setCustomerid(openid);
        order.setShopid(device.getShopid());
        order.setDevicesn(sn);
        order.setOrderstatus(OrderKey.待支付);
        order.setCreated(new Date(currentTime));
        order.setPaytype(OrderKey.PAY_微信);
        order.setAmount(shopMenu.getPrice());
        order.setTime(shopMenu.getTime() * 60 * 60);
        order.setGkey(shopMenu.getGkey());
        order.setOrderscore(0); // 代表第一次
        order.setEnd(new Date(currentTime + shopMenu.getTime() * 60 * 60 * 1000));
        orderRepository.save(order);
        /************** 设置参数 ***************/

        SortedMap<String, String> signParams = new TreeMap<String, String>();
        signParams.put("appid", WeiXinKey.appid);//app_id
        signParams.put("body", "共城物联-交易订单");//商品参数信息
        signParams.put("mch_id", WeiXinKey.mchid);//微信商户账号
        signParams.put("nonce_str", UUID.randomUUID().toString().replaceAll("-", ""));//32位不重复的编号
        signParams.put("notify_url", WeiXinKey.notify);//回调页面
        signParams.put("out_trade_no", order.getId());//订单编号
        signParams.put("openid", openid);//订单编号
        signParams.put("spbill_create_ip", WeiXinKey.ip);//请求的实际ip地址
        signParams.put("total_fee", ((int)(shopMenu.getPrice() * 100)) + "");//支付金额 单位为分
        signParams.put("trade_type", "JSAPI");
        signParams.put("sign", WeiXinUtils.MD5(signParams));

        /************** 发送微信 ***************/
        String request = WeiXinUtils.MapToXml(signParams);
        String str = HttpClient.httpsRequest(WeiXinKey.unifiedorder, request);

        /************** 解析返回 ***************/

        JSONObject jsonObject = WeiXinUtils.convertXmlIntoJSONObject(str);
        if (null == jsonObject)
            return this.error();
        if (jsonObject.getString("return_code").equalsIgnoreCase("FAIL"))
            return this.error(400, "微信返回错误消息");

        SortedMap<String, String> result = new TreeMap<>();
        if (jsonObject.getString("return_code").equalsIgnoreCase("SUCCESS") &&
            jsonObject.getString("result_code").equalsIgnoreCase("SUCCESS"))
        {
            result.put("appId", jsonObject.getString("appid"));
            result.put("timeStamp", System.currentTimeMillis() / 1000 + "");
            result.put("nonceStr", UUID.randomUUID().toString().replaceAll("-", ""));
            result.put("signType", "MD5");
            result.put("package", "prepay_id=" + jsonObject.getString("prepay_id"));
            result.put("paySign", WeiXinUtils.MD5(result));
        }
        return this.success(result, order);
    }

    @Override
    public Result closeWeixinOrder(String id)
    {
        orderRepository.deleteById(id);

        return this.success();
    }

    @Override
    public void weixinCallback(JSONObject jsonObject)
    {
        Order order = orderRepository.getOrderById(jsonObject.getString("out_trade_no"));
        MoneyLog moneyLog = moneyLogRepository.findMoneyLogByOrderid(
            jsonObject.getString("out_trade_no"));
        if (null != order)
        {
            if (jsonObject.getString("result_code").equalsIgnoreCase("SUCCESS"))
            {
                order.setWeixin(jsonObject.getString("transaction_id"));
                order.setCallback(jsonObject.toJSONString());
                order.setOrderstatus(OrderKey.进行中);
                orderRepository.save(order);
            }
            else
            {
                moneyLogRepository.delete(moneyLog);
                // orderRepository.delete(order);
            }
        }
        else
        {
            moneyLogRepository.delete(moneyLog);
        }
    }

    @Override
    public Result reCharge(String openid, Integer amount)
    {
        MoneyLog moneyLog = new MoneyLog();
        moneyLog.setAmount(amount.floatValue());
        moneyLog.setCreated(new Date());
        moneyLog.setOrderid("WX" + OrderGenerator.OrderId());
        moneyLog.setTargetid(openid);
        moneyLog.setOrdersrc(OrderKey.SEC_充值);
        moneyLog.setMoneytype(OrderKey.SEC_充值);
        moneyLog.setRemark("微信充值");
        moneyLogRepository.save(moneyLog);

        SortedMap<String, String> signParams = new TreeMap<String, String>();
        signParams.put("appid", WeiXinKey.appid);//app_id
        signParams.put("body", "共城宝-订单");//商品参数信息
        signParams.put("mch_id", WeiXinKey.mchid);//微信商户账号
        signParams.put("nonce_str", UUID.randomUUID().toString().replaceAll("-", ""));//32位不重复的编号
        signParams.put("notify_url", WeiXinKey.notify);//回调页面
        signParams.put("out_trade_no", moneyLog.getOrderid());//订单编号
        signParams.put("openid", openid);//订单编号
        signParams.put("spbill_create_ip", WeiXinKey.ip);//请求的实际ip地址
        signParams.put("total_fee", (amount * 100) + "");//支付金额 单位为分
        signParams.put("trade_type", "JSAPI");
        signParams.put("sign", WeiXinUtils.MD5(signParams));

        /************** 发送微信 ***************/
        String request = WeiXinUtils.MapToXml(signParams);
        String str = HttpClient.httpsRequest(WeiXinKey.unifiedorder, request);

        /************** 解析返回 ***************/

        JSONObject jsonObject = WeiXinUtils.convertXmlIntoJSONObject(str);
        if (null == jsonObject)
            return this.error();
        if (jsonObject.getString("return_code").equalsIgnoreCase("FAIL"))
            return this.error(400, "微信返回错误消息");

        SortedMap<String, String> result = new TreeMap<>();
        if (jsonObject.getString("return_code").equalsIgnoreCase("SUCCESS") &&
            jsonObject.getString("result_code").equalsIgnoreCase("SUCCESS"))
        {
            result.put("appId", jsonObject.getString("appid"));
            result.put("timeStamp", System.currentTimeMillis() / 1000 + "");
            result.put("nonceStr", UUID.randomUUID().toString().replaceAll("-", ""));
            result.put("signType", "MD5");
            result.put("package", "prepay_id=" + jsonObject.getString("prepay_id"));
            result.put("paySign", WeiXinUtils.MD5(result));
        }
        return this.success(result, moneyLog);
    }

    @Override
    public Result reChargeCallBack(String openid, Integer id, String status)
    {
        MoneyLog moneyLog = moneyLogRepository.findMoneyLogById(id);
        if (null == moneyLog)
            return this.error();
        if (status.equalsIgnoreCase("success"))
        {
            Account account = accountRepository.findAccountByOpenid(openid);
            account.setBalance(account.getBalance() + moneyLog.getAmount());
            account.setIntegral(account.getIntegral() + moneyLog.getAmount().intValue());
            accountRepository.saveAndFlush(account);
        }
        else
        {
            moneyLogRepository.delete(moneyLog);
        }
        return this.success();
    }
}
